package com.hzbank.generate;

import com.hzbank.generate.entity.AccountDetails;
import com.hzbank.generate.entity.AccountInfo;
import com.hzbank.generate.mapper.AccountDetailsMapper;
import com.hzbank.generate.mapper.AccountInfoMapper;
import com.hzbank.generate.mapper.EntityMapper;
import com.hzbank.generate.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

@Slf4j
@Service
@Transactional
public class ServiceoMain {
    Random random = new Random();

    String maccNo = ""; //账号
    double mmoneyInt;//交易金额
    BigDecimal balBefore1;//交易前金额1
    BigDecimal balBefore2;//交易前金额2
    BigDecimal balAfter1;//交易后金额1
    BigDecimal balAfter2;//交易后金额2
    String mOpnDt = ""; //开户日期

    // 卡Bin
    String[] crdBins = {"623083","623084","623085","623086","623087","623088","623089"};
    // 渠道
    String[] tchanlCode = {"00","01","02","04","05","09"};
    //币种
    String[] mccy = {"156","158","344","392","446","756","764","826","840","910"};
    // 摘要
    String[] mMemo = {"0000","0001","0003","0004","0005","0006","0007","0008","1001","1002","2001","9999"};

    @Autowired
    private AccountInfoMapper accountInfoMapper;
    @Autowired
    private AccountDetailsMapper accountDetailsMapper;
    @Autowired
    private EntityMapper entityMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisUtil redisUtil;

    public Map<String,Object> count(){
        Map<String,Object> countMap = new HashMap<>();
        Map<String,Object> countMapRedis = (Map<String, Object>) redisTemplate.opsForValue().get("countMap");
        if(countMapRedis == null){
            int countInfo = accountInfoMapper.countInfo();
            int countDetails = accountDetailsMapper.countDetails();
            countMap.put("账户信息条数:",countInfo);
            countMap.put("明细条数",countDetails);
            redisTemplate.opsForValue().set("countMap",countMap);
            //redisTemplate.expire("countMap",20, TimeUnit.SECONDS); //20秒过期
            redisUtil.expire("countMap",20);
        }else {
            countMap = countMapRedis;
        }

        return countMap;

    }

    // 指定使用beanname为doSomethingExecutor的线程池
    @Async("doExecutor")
    public void generate(String msg){
        long startWhole = System.currentTimeMillis();
        //1、生成1~100的随机整数
        int rd = (int) (Math.random()*100+1);
        log.info("龙={}",msg);
        if (rd == 50){
            //若值为50则生成新的账户数据
            createNewAccountInof();
        }else {
            // 否则生成交易数据；
            createNewDetailsBytransfer();
        }
        log.info("第" + msg + "条执行结束！耗时" + (System.currentTimeMillis()-startWhole));
    }

    /**
     * 生成新的交易数据
     */
    private void createNewDetailsBytransfer() {
        long maxTime = System.currentTimeMillis();
        int max = accountInfoMapper.selectMaxAccId();
        log.info("查询最大值！耗时：" + (System.currentTimeMillis()-maxTime) );
        if(max < 1){  //当用户量少于1
            createNewAccountInof(); //新增
            createNewAccountInof();
        } else if(max == 1){
            createNewAccountInof();
        }else
        {
            int trandom1 = random.nextInt(max);
            int trandom2 = random.nextInt(max);
            while (trandom1 == trandom2){
                trandom2 = random.nextInt(max);
            }
            long start = System.currentTimeMillis();
            AccountInfo accountInfo1 = accountInfoMapper.selectInfoByPrimaryKey(trandom1+1);
            long end = System.currentTimeMillis();
            log.info("随机查出第一条账户信息！耗时：" + (end-start) );
            AccountInfo accountInfo2 = accountInfoMapper.selectInfoByPrimaryKey(trandom2+1);
            log.info("随机查出第二条账户信息！耗时：" + (System.currentTimeMillis()-end) );

            int a = random.nextInt(2);
            if (a == 0){  //账号1 转出  账号2转入
                //两个账户表金额发生改变
                transferAccounts(accountInfo1, accountInfo2);
                // 转账产生明细表生成数据
                generateDetailsBytransfer(accountInfo1, accountInfo2);
            } else {   //账号2 转出 账号1转入
                //两个账户表金额发生改变
                transferAccounts(accountInfo2, accountInfo1);
                // 转账产生明细表生成数据
                generateDetailsBytransfer(accountInfo2, accountInfo1);
            }
        }

    }

    /**
     * 转账产生明细
     * @param accountInfo1
     * @param accountInfo2
     */
    private void generateDetailsBytransfer(AccountInfo accountInfo1, AccountInfo accountInfo2) {
        AccountDetails accountDetails1 = new AccountDetails();
        AccountDetails accountDetails2 = new AccountDetails();
        //交易日期
        int year = random.nextInt(21); //年
        int month = random.nextInt(12)+1;//月
        int day  = random.nextInt(27)+1;//日
        String year1 = String.format("%02d", year);
        String month1 = String.format("%02d", month);
        String day1 = String.format("%02d", day);
        String ttradeDT = "20";
        ttradeDT = ttradeDT +year1+ "-" +month1+ "-" +day1;
        // 时间戳
        LocalDateTime now = LocalDateTime.now();
        String nowTime = now.format(DateTimeFormatter.ofPattern("HHmmssSSS"));
        // 随机数
        int trandom = random.nextInt(98);
        String ttrandom = String.format("%02d",trandom);
        //交易流水 :时间戳+随机数
        String ttranSeq = "20" + year1 + month1 + day1+ nowTime + ttrandom;
        //网点号
        long startAreaCode = System.currentTimeMillis();
        String tAreaCode = entityMapper.selectOneBsOrgaBase().getAreaCode();
        log.info("查询最大值！耗时：" + (System.currentTimeMillis()-startAreaCode) );
        //摘要
        String tMemo = mMemo[random.nextInt(mMemo.length)];
        //币种
        String tCcy = createCcy();
        //渠道号
        String tChanlCode = tchanlCode[random.nextInt(tchanlCode.length)];
        //交易类型  随机四位
        String ttranType = String.format("%04d",random.nextInt(9999));
        //当前时间
        String ttranTime = new SimpleDateFormat("HH:mm:ss").format(new Date());
        String ttranSts = String.valueOf(random.nextInt(2)); // 交易状态

        accountDetails1.setTranDt(ttradeDT);//交易日期
        accountDetails1.setTranSeq(ttranSeq);//交易流水号
        accountDetails1.setSeqNo(1);//流水序号
        accountDetails1.setCustNo(accountInfo1.getCustNo());//客户号
        accountDetails1.setAccNo(accountInfo1.getAccNo());//账号
        accountDetails1.setOppAccNo(accountInfo2.getAccNo());// 对方账号
        accountDetails1.setAreaCode(tAreaCode);//网点号(归属机构)
        accountDetails1.setMemo(tMemo);//摘要 0009 转账
        accountDetails1.setCcy(tCcy);//币种
        accountDetails1.setChanlCode(tChanlCode);//渠道号
        accountDetails1.setDcFlag("1");//借贷标识 0开户，1转出  2转入
        accountDetails1.setTranType(ttranType);//交易类型
        accountDetails1.setTranTime(ttranTime);//交易时间
        accountDetails1.setTranAmt(new BigDecimal(mmoneyInt));//交易金额
        accountDetails1.setTranPreAmt(balBefore1);//交易前金额
        accountDetails1.setTranAftAmt(balAfter1);//交易后金额
        accountDetails1.setTranSts(ttranSts);//交易状态 0

        accountDetails2.setTranDt(ttradeDT);//交易日期
        accountDetails2.setTranSeq(ttranSeq);//交易流水号
        accountDetails2.setSeqNo(2); //流水序号
        accountDetails2.setCustNo(accountInfo2.getCustNo());//客户号
        accountDetails2.setAccNo(accountInfo2.getAccNo());//账号
        accountDetails2.setOppAccNo(accountInfo1.getAccNo());// 对方账号
        accountDetails2.setAreaCode(tAreaCode);//网点号(归属机构)
        accountDetails2.setMemo("0009");//摘要 0009 转账
        accountDetails2.setCcy(tCcy);//币种
        accountDetails2.setChanlCode(tChanlCode);//渠道号
        accountDetails2.setDcFlag("2");//借贷标识 0开户，1转出  2转入
        accountDetails2.setTranType(ttranType);//交易类型
        accountDetails2.setTranTime(ttranTime);//交易时间
        accountDetails2.setTranAmt(new BigDecimal(mmoneyInt));//交易金额
        accountDetails2.setTranPreAmt(balBefore2);//交易前金额
        accountDetails2.setTranAftAmt(balAfter2);//交易后金额
        accountDetails2.setTranSts(ttranSts);//交易状态 0

        long start1 = System.currentTimeMillis();
        accountDetailsMapper.insert(accountDetails1);
        long end = System.currentTimeMillis();
        log.info("Details表插入数据1结束！耗时：" + (System.currentTimeMillis() - start1) );
        accountDetailsMapper.insert(accountDetails2);
        log.info("Details表插入数据2结束！耗时：" + (end-start1) );
    }

    /**
     * 人民币使用率更高
     * @return
     */
    private String createCcy() {
        int n = random.nextInt(100);
        if(n%10 != 0){
            return "156";
        }else {
            return mccy[random.nextInt(mccy.length)];
        }
    }

    /**
     * 两个账户表金额发生改变
     * @param accountInfoOutput
     * @param accountInfoInput
     */
    private void transferAccounts(AccountInfo accountInfoOutput, AccountInfo accountInfoInput) {
        balBefore1 = accountInfoOutput.getBal();
        balBefore2 = accountInfoInput.getBal();
        double tmoney = random.nextInt(9999999);
        mmoneyInt = tmoney/100;
        while (balBefore1.intValue() < mmoneyInt){
            tmoney = random.nextInt(9999999);
            mmoneyInt = tmoney/100;
        }
        //log.info(tmoney+"===="+mmoneyInt);
        BigDecimal moneyBigCimal1 = new BigDecimal(mmoneyInt);

        //第一个账户减随机金额
        balAfter1 = balBefore1.subtract(moneyBigCimal1);
        accountInfoOutput.setBal(balAfter1);
        //第二个账户加相同金额
        balAfter2 = balBefore2.add(moneyBigCimal1);
        accountInfoInput.setBal(balAfter2);
        try {
            long start = System.currentTimeMillis();
            accountInfoMapper.update(accountInfoOutput);
            long end = System.currentTimeMillis();
            log.info("Info表跟新第1条数据结束！耗时： " + (end - start));
            accountInfoMapper.update(accountInfoInput);
            log.info("Info表跟新第2条数据结束！耗时： " + (System.currentTimeMillis() - end) );
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 生成新的账户数据
     */
    private void createNewAccountInof() {
        int n = random.nextInt(1000000);
        String tCusNo = "72"+String.format("%07d",n);

        // 开户日期
        int year = random.nextInt(21); //年
        int month = random.nextInt(12)+1;//月
        int day  = random.nextInt(27)+1;//日
        String year1 = String.format("%02d", year);
        String month1 = String.format("%02d", month);
        String day1 = String.format("%02d", day);
        String ttradeDT = "20";
        mOpnDt = ttradeDT +year1+ "-" +month1+ "-" +day1;
        // 时间戳
        LocalDateTime now = LocalDateTime.now();
        String nowTime = now.format(DateTimeFormatter.ofPattern("HHmmssSSS"));
        //开户机构
        long startBrcNo = System.currentTimeMillis();
        String tBrcNo = entityMapper.selectOneBsOrgaBase().getAreaCode();
        log.info("随机查询开户机构！耗时：" + (System.currentTimeMillis()-startBrcNo) );
        //随机数两位数
        int trandom = random.nextInt(99);
        String ttrandom = String.format("%02d",trandom);
        //随机数 一位
        int rd = (int) (Math.random()*10);
        //账号
        maccNo = crdBins[random.nextInt(crdBins.length)] + "20" +year1 + month1 + day1 + nowTime + rd;
        //账户余额/开户金额 随机10w
        int tbal = (int) (Math.random()*100000+1);//随机数 10w
        AccountInfo accountInfo =new AccountInfo();
        accountInfo.setAccNo(maccNo); //账号
        accountInfo.setCustNo(tCusNo); // 客户号
        accountInfo.setOpnDt(mOpnDt); // 开户日期
        accountInfo.setChannelCode(tchanlCode[random.nextInt(tchanlCode.length)]); // 开户渠道
        accountInfo.setBrcNo(tBrcNo); // 开户机构
        accountInfo.setOperNo(tBrcNo+ttrandom); //推荐人 开户机构+序号
        accountInfo.setBal(new BigDecimal(String.valueOf(tbal)));//账户余额

        long start = System.currentTimeMillis();
        accountInfoMapper.insert(accountInfo);
        log.info("Info表插入数据结束！耗时：" + (System.currentTimeMillis() - start) );
        /**
         * 如果开户金额为0的数据，在交易明细中没有记录，
         * 只有账户数据；如果开户金额非0，则在交易明细中插入交易明细
         */
        if (tbal != 0){

            AccountDetails accountDetails = new AccountDetails();
            //交易流水 :时间戳+随机数
            String ttranSeq = "20"+year1 + month1 + day1 + nowTime + ttrandom;
            // 交易类型  随机四位
            String ttranType = String.format("%04d",random.nextInt(9999));
            //当前时间
            String ttranTime = new SimpleDateFormat("HH:mm:ss").format(new Date());
            //网点号
            long startAreaCode = System.currentTimeMillis();
            String tAreaCode = entityMapper.selectOneBsOrgaBase().getAreaCode();
            log.info("随机查询网点号！耗时：" + (System.currentTimeMillis()-startAreaCode) );

            accountDetails.setTranDt(mOpnDt);//交易日期
            accountDetails.setTranSeq(ttranSeq);//交易流水号
            accountDetails.setSeqNo(1); // 流水序号
            accountDetails.setCustNo(accountInfo.getCustNo());//客户号
            accountDetails.setAccNo(accountInfo.getAccNo());//账号
            accountDetails.setAreaCode(tAreaCode);//网点号(归属机构)
            accountDetails.setMemo("0000");//摘要  开户
            accountDetails.setCcy("156");//币种 开户不能是外币
            accountDetails.setChanlCode(tchanlCode[random.nextInt(tchanlCode.length)]);//渠道号
            accountDetails.setDcFlag("0");//借贷标识 0开户，1转出  2转入
            accountDetails.setTranType(ttranType);//交易类型
            accountDetails.setTranTime(ttranTime);//交易时间
            accountDetails.setTranAmt(accountInfo.getBal());//交易金额
            accountDetails.setTranPreAmt(new BigDecimal(String.valueOf(tbal)));
            accountDetails.setTranAftAmt(new BigDecimal(String.valueOf(tbal)));
            accountDetails.setTranSts(String.valueOf(random.nextInt(2)));//交易状态 0
            long start2 = System.currentTimeMillis();
            accountDetailsMapper.insert(accountDetails);
            log.info("Details表插入数据结束！" + (System.currentTimeMillis() - start2) );
        }
    }

}
